#!/bin/bash
#
# CP2K Darwin arch file for a parallel arm64 binary
# (https://www.cp2k.org/howto:compile_on_macos)
#
# Tested with: GNU 14.1.0, OpenMPI 4.1.6,,
#              ScaLAPACK 2.2.1, OpenBLAS 0.3.27,
#              FFTW 3.3.10, HDF5 1.14.3,
#              LIBINT 2.6.0, LIBXC 6.2.2,
#              SPGLIB 2.3.1, PLUMED 2.9.0,
#              LIBVORI 220621, GSL 2.7.1,
#              COSMA 2.6.6, SIRIUS 7.5.2,
#              LIBGRPP 20231215,
#              SPFFT 1.0.6, SPLA 1.6.0
# on an Apple M1 (macOS 14.5.0 Sonoma)
#
# Usage: Source this arch file and then run make as instructed.
#        Ensure the links in /opt/homebrew/bin to the gcc version
#        and "brew unlink openmpi" (or mpich) if installed.
#
# Last update: 11.06.2024
#
# \
   if [[ "${0}" == "${BASH_SOURCE}" ]]; then \
      echo "ERROR: Script ${0##*/} must be sourced"; \
      echo "Usage: source ${0##*/}"; \
      exit 1; \
   fi; \
   this_file=${BASH_SOURCE##*/}; \
   cd tools/toolchain; \
   rm -rf build; \
   [[ -z "${mpi_implementation}" ]] && mpi_implementation="openmpi"; \
   [[ -z "${target_cpu}" ]] && target_cpu="native"; \
   if $(command -v brew >/dev/null 2>&1); then \
      brew install cmake; \
      brew install coreutils; \
      brew install fftw; \
      brew install gcc; \
      brew install gsed; \
      brew install gsl; \
      brew install hdf5; \
      brew install libxc; \
      brew install openblas; \
      brew install pkg-config; \
      brew install wget; \
   else \
      echo "ERROR: Homebrew installation not found"; \
      echo '  Run: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'; \
      cd ../..; \
      return 1; \
   fi; \
   ./install_cp2k_toolchain.sh --install-all -j${maxtasks} --no-arch-files --target-cpu=${target_cpu} \
      --with-cmake=$(brew --prefix cmake) --with-elpa=no --with-fftw=$(brew --prefix fftw) --with-gcc=system \
      --with-gsl=$(brew --prefix gsl) --with-hdf5=$(brew --prefix hdf5) --with-libxc=$(brew --prefix libxc) \
      --with-libxsmm=no --with-openblas=$(brew --prefix openblas) --with-${mpi_implementation} \
      --with-pexsi=no --with-quip=no; \
   source ./install/setup; \
   cd ../..; \
   echo; \
   echo "Check the output above for error messages and consistency!"; \
   echo; \
   echo "If everything is OK, you can build a CP2K production binary with"; \
   echo "   make -j ARCH=${this_file%.*} VERSION=${this_file##*.}"; \
   echo; \
   echo "Alternatively, you can add further checks, e.g. for regression testing, with"; \
   echo "   make -j ARCH=${this_file%.*} VERSION=${this_file##*.} DO_CHECKS=yes"; \
   echo; \
   echo "Run always the following command before using the CP2K binary"; \
   echo "   source ${PWD}/tools/toolchain/install/setup"; \
   echo; \
   return

# Set options
DO_CHECKS      := no
TARGET_CPU     := native
USE_COSMA      := 2.6.6
USE_LIBGRPP    := 20231215
USE_LIBINT     := 2.6.0
USE_LIBVORI    := 220621
USE_PLUMED     := 2.9.0
USE_SCALAPACK  := 2.2.1
USE_SIRIUS     := 7.5.2
USE_SPFFT      := 1.0.6
USE_SPGLIB     := 2.3.1
USE_SPLA       := 1.6.0
# Only needed for SIRIUS
LIBVDWXC_VER   := 0.4.0

LMAX           := 5
MAX_CONTR      := 4

CC             := mpicc
FC             := mpifort
LD             := mpifort
AR             := ar -r -s

CFLAGS         := -O2 -fopenmp -fopenmp-simd -ftree-vectorize -funroll-loops -g -mtune=$(TARGET_CPU)

DFLAGS         := -D__parallel
DFLAGS         += -D__SCALAPACK
DFLAGS         += -D__ACCELERATE
DFLAGS         += -D__HAS_IEEE_EXCEPTIONS
DFLAGS         += -D__MAX_CONTR=$(strip $(MAX_CONTR))
DFLAGS         += -D__NO_STATM_ACCESS

INSTALL_PATH   := $(PWD)/tools/toolchain/install

# Settings for regression testing
ifeq ($(DO_CHECKS), yes)
   DFLAGS         += -D__CHECK_DIAG
   FCFLAGS_DEBUG  := -fcheck=bounds,do,recursion,pointer
   FCFLAGS_DEBUG  += -fcheck=all,no-array-temps
#  FCFLAGS_DEBUG  += -ffpe-trap=invalid,overflow,zero
   FCFLAGS_DEBUG  += -fimplicit-none
   FCFLAGS_DEBUG  += -finit-derived
   FCFLAGS_DEBUG  += -finit-real=snan
   FCFLAGS_DEBUG  += -finit-integer=-42
   FCFLAGS_DEBUG  += -finline-matmul-limit=0
   WFLAGS         := -Werror=aliasing
   WFLAGS         += -Werror=ampersand
   WFLAGS         += -Werror=c-binding-type
   WFLAGS         += -Werror=conversion
   WFLAGS         += -Werror=intrinsic-shadow
   WFLAGS         += -Werror=intrinsics-std
   WFLAGS         += -Werror=line-truncation
   WFLAGS         += -Wrealloc-lhs
   WFLAGS         += -Werror=tabs
   WFLAGS         += -Werror=target-lifetime
   WFLAGS         += -Werror=underflow
   WFLAGS         += -Werror=unused-but-set-variable
   WFLAGS         += -Werror=unused-dummy-argument
   WFLAGS         += -Werror=unused-variable
endif

ifneq ($(USE_PLUMED),)
   USE_GSL        := 2.7
   USE_PLUMED     := $(strip $(USE_PLUMED))
   PLUMED_LIB     := $(INSTALL_PATH)/plumed-$(USE_PLUMED)/lib
   DFLAGS         += -D__PLUMED2
   LIBS           += $(PLUMED_LIB)/libplumed.a
endif

ifneq ($(USE_LIBVORI),)
   USE_LIBVORI    := $(strip $(USE_LIBVORI))
   LIBVORI_LIB    := $(INSTALL_PATH)/libvori-$(USE_LIBVORI)/lib
   DFLAGS         += -D__LIBVORI
   LIBS           += $(LIBVORI_LIB)/libvori.a
endif

LIBXC_HOME     := $(shell brew --prefix libxc)
CFLAGS         += -I$(LIBXC_HOME)/include
DFLAGS         += -D__LIBXC
LIBS           += -Wl,-rpath,$(LIBXC_HOME)/lib -L$(LIBXC_HOME)/lib -lxcf03 -lxc

ifneq ($(USE_LIBGRPP),)
   USE_LIBGRPP    := $(strip $(USE_LIBGRPP))
   LIBGRPP_INC    := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/include
   LIBGRPP_LIB    := $(INSTALL_PATH)/libgrpp-main-$(USE_LIBGRPP)/lib
   CFLAGS         += -I$(LIBGRPP_INC)
   DFLAGS         += -D__LIBGRPP
   LIBS           += $(LIBGRPP_LIB)/liblibgrpp.a
endif

ifneq ($(USE_LIBINT),)
   USE_LIBINT     := $(strip $(USE_LIBINT))
   LMAX           := $(strip $(LMAX))
   LIBINT_INC     := $(INSTALL_PATH)/libint-v$(USE_LIBINT)-cp2k-lmax-$(LMAX)/include
   LIBINT_LIB     := $(INSTALL_PATH)/libint-v$(USE_LIBINT)-cp2k-lmax-$(LMAX)/lib
   CFLAGS         += -I$(LIBINT_INC)
   DFLAGS         += -D__LIBINT
   LIBS           += $(LIBINT_LIB)/libint2.a
   LIBS           += $(LIBINT_LIB)/libint2.a
endif

ifneq ($(USE_SPGLIB),)
   USE_SPGLIB     := $(strip $(USE_SPGLIB))
   SPGLIB_INC     := $(INSTALL_PATH)/spglib-$(USE_SPGLIB)/include
   SPGLIB_LIB     := $(INSTALL_PATH)/spglib-$(USE_SPGLIB)/lib
   CFLAGS         += -I$(SPGLIB_INC)
   DFLAGS         += -D__SPGLIB
   LIBS           += $(SPGLIB_LIB)/libsymspg.a
endif

ifneq ($(USE_SIRIUS),)
   USE_SIRIUS     := $(strip $(USE_SIRIUS))
   LIBVDWXC_VER   := $(strip $(LIBVDWXC_VER))
   LIBVDWXC_INC   := $(INSTALL_PATH)/libvdwxc-$(LIBVDWXC_VER)/include
   LIBVDWXC_LIB   := $(INSTALL_PATH)/libvdwxc-$(LIBVDWXC_VER)/lib
   SIRIUS_INC     := $(INSTALL_PATH)/sirius-$(USE_SIRIUS)/include
   SIRIUS_LIB     := $(INSTALL_PATH)/sirius-$(USE_SIRIUS)/lib
   CFLAGS         += -I$(LIBVDWXC_INC)
   CFLAGS         += -I$(SIRIUS_INC)
   DFLAGS         += -D__LIBVDWXC
   DFLAGS         += -D__SIRIUS
   LIBS           += $(SIRIUS_LIB)/libsirius.a
   LIBS           += $(LIBVDWXC_LIB)/libvdwxc.a
endif

ifneq ($(USE_SPFFT),)
   USE_SPFFT      := $(strip $(USE_SPFFT))
   SPFFT_INC      := $(INSTALL_PATH)/SpFFT-$(USE_SPFFT)/include
   SPFFT_LIB      := $(INSTALL_PATH)/SpFFT-$(USE_SPFFT)/lib
   CFLAGS         += -I$(SPFFT_INC)
   DFLAGS         += -D__SPFFT
   LIBS           += $(SPFFT_LIB)/libspfft.a
endif

ifneq ($(USE_SPLA),)
   USE_SPLA       := $(strip $(USE_SPLA))
   SPLA_INC       := $(INSTALL_PATH)/SpLA-$(USE_SPLA)/include/spla
   SPLA_LIB       := $(INSTALL_PATH)/SpLA-$(USE_SPLA)/lib
   CFLAGS         += -I$(SPLA_INC)
   DFLAGS         += -D__SPLA
   LIBS           += $(SPLA_LIB)/libspla.a
endif

HDF5_HOME      := $(shell brew --prefix hdf5)
CFLAGS         += -I$(HDF5_HOME)/include
DFLAGS         += -D__HDF5
LIBS           += $(HDF5_HOME)/lib/libhdf5_fortran.a
LIBS           += $(HDF5_HOME)/lib/libhdf5_f90cstub.a
LIBS           += $(HDF5_HOME)/lib/libhdf5.a
LIBS           += $(shell brew --prefix libaec)/lib/libsz.a

ifneq ($(USE_COSMA),)
   USE_COSMA      := $(strip $(USE_COSMA))
   COSMA_INC      := $(INSTALL_PATH)/COSMA-$(USE_COSMA)/include
   COSMA_LIB      := $(INSTALL_PATH)/COSMA-$(USE_COSMA)/lib
   CFLAGS         += -I$(COSMA_INC)
   DFLAGS         += -D__COSMA
   LIBS           += $(COSMA_LIB)/libcosma_prefixed_pxgemm.a
   LIBS           += $(COSMA_LIB)/libcosma.a
   LIBS           += $(COSMA_LIB)/libcosta.a
endif

FFTW_HOME      := $(shell brew --prefix fftw)
CFLAGS         += -I$(FFTW_HOME)/include
DFLAGS         += -D__FFTW3
LIBS           += $(FFTW_HOME)/lib/libfftw3_mpi.a
LIBS           += $(FFTW_HOME)/lib/libfftw3_omp.a
LIBS           += $(FFTW_HOME)/lib/libfftw3.a

USE_SCALAPACK  := $(strip $(USE_SCALAPACK))
LIBS           += $(INSTALL_PATH)/scalapack-$(USE_SCALAPACK)/lib/libscalapack.a

GSL_HOME       := $(shell brew --prefix gsl)
CFLAGS         += -I$(GSL_HOME)/include
DFLAGS         += -D__GSL
LIBS           += $(GSL_HOME)/lib/libgsl.a

OPENBLAS_HOME  := $(shell brew --prefix openblas)
CFLAGS         += -I$(OPENBLAS_HOME)/include
LIBS           += $(OPENBLAS_HOME)/lib/libopenblas.a

CFLAGS         += $(DFLAGS)

FCFLAGS        := $(CFLAGS) $(FCFLAGS_DEBUG) $(WFLAGS)
FCFLAGS        += -fallow-argument-mismatch
FCFLAGS        += -fbacktrace
FCFLAGS        += -ffree-form
FCFLAGS        += -ffree-line-length-none
FCFLAGS        += -fno-omit-frame-pointer
FCFLAGS        += -std=f2008

LDFLAGS        += $(FCFLAGS) -ld_classic

LIBS           += -lz -ldl -lstdc++

# End
